﻿/*************************************************************************************
 * 工    具：  HK_CircularSlider
 * 
 * 描    述： 基于 Unity 的自定义圆形滑块工具脚本，用于在游戏或应用中创建圆形滑块控件。
 *           该控件允许用户通过拖动来选择一个介于 0 到 1 之间的值，并且可以根据用户的设置进行顺时针或逆时针滑动。
 * 
 * 版    本：  V1.0
 * 作    者：  京产肠饭
 * 
 * 创    建：  2025/01/08  V1.0
 *
 *            
 * 链   接：   https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using QFramework;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace HKTools
{
    public enum HK_CircularSliderInitType
    {
        Top,
        Bottom,
        // Left,
        // Right,
    }

    public enum HK_CircularSliderDirType
    {
        顺时针,
        逆时针,
    }

    public class HK_CircularSlider : MonoBehaviour
    {
        // 0 -- 1 的值，作为响应式属性对外使用 
        public BindableProperty<float> Value = new BindableProperty<float>();

        [Header("当前值："), SerializeField] float value;

        [Header("是否限制："), SerializeField] bool isLock = true;

        [Header("初始方向："), SerializeField] HK_CircularSliderInitType initType = HK_CircularSliderInitType.Top;
        [Header("滑动方向："), SerializeField] HK_CircularSliderDirType dirType;

        [Header("滑动的Handle："), SerializeField] RectTransform handle;
        [Header("半径："), SerializeField] float radius = 50f;

        [Header("触控区域："), SerializeField] Image touchArea;
        [Header("填充区域："), SerializeField] Image fillArea;

        float currentAngle = 0f;
        float startAngleOffset = 0f;

        void Start()
        {
            Value.RegisterWithInitValue(value =>
            {
                this.value = value;
            }).UnRegisterWhenGameObjectDestroyed(gameObject);

            touchArea.alphaHitTestMinimumThreshold = 0.1f;
            touchArea.raycastTarget = true;

            fillArea.fillClockwise = dirType == HK_CircularSliderDirType.顺时针;

            fillArea.raycastTarget = false;
            handle.GetComponent<Image>().raycastTarget = false;

            switch (initType)
            {
                case HK_CircularSliderInitType.Top:
                    startAngleOffset = 90f;
                    fillArea.fillOrigin = 2;
                    break;
                case HK_CircularSliderInitType.Bottom:
                    startAngleOffset = 270f;
                    fillArea.fillOrigin = 0;
                    break;
                    // case HK_CircularSliderInitType.Left:
                    //     startAngleOffset = 180f;
                    //     fillArea.fillOrigin = 3;
                    //     break;
                    // case HK_CircularSliderInitType.Right:
                    //     startAngleOffset = 0f;
                    //     fillArea.fillOrigin = 1;
                    //     break;
            }

            UpdateUIAndValue();

            var trigger = touchArea.GetComponent<EventTrigger>();
            var entry = new EventTrigger.Entry { eventID = EventTriggerType.Drag };
            entry.callback.AddListener(data => OnSliderDrag(data as PointerEventData));
            trigger.triggers.Add(entry);
        }

        // Slider拖动回调
        void OnSliderDrag(PointerEventData eventData)
        {
            // 将鼠标位置转为局部坐标
            Vector2 mouseDir = eventData.position - (Vector2)transform.position;

            float angle = Mathf.Atan2(mouseDir.y, dirType == 0 ? -mouseDir.x : mouseDir.x) * Mathf.Rad2Deg;

            angle = (angle < 0 ? angle + 360f : angle) - startAngleOffset;
            angle = (angle < 0) ? angle + 360f : angle;

            if (isLock)
            {
                // 限制currentAngle的值在5到355之间  
                if (currentAngle < 5f)
                {
                    if (angle < currentAngle || angle > 180)
                        return;

                    currentAngle = 5f;
                }
                else if (currentAngle > 355f)
                {
                    if (angle > currentAngle || angle < 180)
                        return;

                    currentAngle = 355f;
                }
                else
                {
                    currentAngle = angle;
                }
            }
            else
            {
                currentAngle = angle;
            }

            UpdateUIAndValue();
        }


        // 更新UI填充  
        void UpdateUIAndValue()
        {
            float radian;

            if (isLock)
            {
                if (currentAngle < 6f)
                {
                    radian = startAngleOffset * Mathf.Deg2Rad;

                    fillArea.fillAmount = 0f;
                    Value.Value = 0;
                }
                else if (currentAngle > 354f)
                {
                    radian = (359 + startAngleOffset) * Mathf.Deg2Rad;

                    fillArea.fillAmount = 1f;
                    Value.Value = 1;
                }
                else
                {
                    radian = (currentAngle + startAngleOffset) * Mathf.Deg2Rad;

                    float fill = currentAngle / 360f;
                    fillArea.fillAmount = fill;
                    Value.Value = fill;
                }
            }
            else
            {
                radian = (currentAngle + startAngleOffset) * Mathf.Deg2Rad;

                float fill = currentAngle / 360f;
                fillArea.fillAmount = fill;
                Value.Value = fill;
            }

            // 根据滑动方向调整角度偏移
            if (dirType == HK_CircularSliderDirType.顺时针)
            {
                if (initType == HK_CircularSliderInitType.Top || initType == HK_CircularSliderInitType.Bottom)
                    radian = Mathf.PI - radian; // 逆时针方向，角度取反
                // else
                //     radian = 2 * Mathf.PI - radian; // 顺时针方向，角度取反
            }

            Vector2 newPos = new Vector2(Mathf.Cos(radian), Mathf.Sin(radian)) * radius;
            handle.localPosition = newPos;
        }
    }
}